var Mongoose = require('mongoose'),
    Bcrypt = require('bcryptjs'),
    fs = require('fs'),
    crypto = require('crypto'),
    config = require('../config/config'),
    util = require('../helpers/util');

// User schema
var UserSchema = Mongoose.Schema({
    firstName: {
        type: String,
        required: true,
        trim: true
    },
    lastName: {
        type: String,
        trim: true
    },
    email: {
        type: String,
        required: true,
        unique: true
    },
    password: {
        type: String
    },
    country: {
        type: String,
        trim: true,
        default: ''
    },
    state: {
        type: String,
        trim: true,
        default: ''
    },
    city: {
        type: String,
        trim: true,
        default: ''
    },
    address: {
        type: String,
        trim: true,
        default: ''
    },
    aboutMe: {
        type: String,
        trim: true,
        default: ''
    },
    isActive: {
        type: Boolean,
        default: true
    },
    isVerified: {
        type: Boolean,
        default: false
    },
    role: {
        type: [String],
        default: ['user']
    },
    confirmationToken: {
        type: String,
        default: ''
    },
    passwordResetToken: {
        type: String,
        default: ''
    },
    version: {
        type: String,
        default: ''
    },
    gender: {
        type: String,
        default: ''
    },
    modules: {
        type: [String],
        default: ['']
    },
    profileImageURL: {
        type: String,
        default: './profileUploads/default.png'
    },
    savedIdea: {}
}, {timestamps: true});

var User = Mongoose.model('User', UserSchema);

UserSchema.pre('save', function (next) {
    var self = this;
    if (this.password && this.isModified('password')) {
        Bcrypt.genSalt(10, function (err, salt) {
            Bcrypt.hash(self.password, salt, function (err, hash) {
                self.password = hash;
                next();
            });
        });
    } else {
        next();
    }
});

User.createUser = function (newUser, callback) {
    newUser.save(callback);
};

User.getUserByEmail = function (email, callback) {
    User.findOne({email: email}, callback);
};

User.getUserByConfirmationToken = function (token, callback) {
    User.findOne({confirmationToken: token}, callback);
};

User.getUserByPasswordResetToken = function (token, callback) {
    User.findOne({passwordResetToken: token}, callback);
};

User.getUserById = function (id, callback) {
    User.findById(id, callback);
};

User.getAuthor = function (key, callback) {
    var searchMatch = {$or: [{firstName: {$regex: key, $options: '$i'}}, {lastName: {$regex: key, $options: '$i'}}]};
    User.aggregate([
        {$match: searchMatch},
        {
            $lookup: {
                "from": "ideas",
                "localField": "_id",
                "foreignField": "user",
                "as": "idea"
            }
        },
        {$match: {"idea": {$ne: []}}},
        {$limit: 40},
        {
            "$project": {
                _id: 0,
                "title": {$concat: ["$firstName", " ", {$ifNull: ["$lastName", " "]}]}
            }
        }
    ], callback);
};

User.getAllUsers = function (callback) {
    User.find({},
        {
            'password': 0,
            '_id': 0,
            '__v': 0,
            'isVerified': 0,
            'confirmationToken': 0,
            'passwordResetToken': 0
        }, callback);
};

User.comparePassword = function (candidatePassword, hash, callback) {
    Bcrypt.compare(candidatePassword, hash, function (err, isMatch) {
        if (err) {
            throw  err;
        }
        callback(null, isMatch);
    });
};

User.updateConfirmationToken = function (confirmationToken, callback) {
    User.update({$set: {confirmationToken: confirmationToken}}, callback);
};

User.viewProfile = function (id, callback) {
    User.findOne({_id: id}, {
        'password': 0,
        'isActive': 0,
        'updatedAt': 0,
        '__v': 0,
        'isVerified': 0,
        'confirmationToken': 0,
        'passwordResetToken': 0
    }, callback);
};

User.uploadCropped = function (data, UserID, callback) {
    crypto.randomBytes(10, function (err, buffer) {
        var token = buffer.toString('hex');
        var imagePath = config.uploads.profileUpload.dest + token + '.' + data.fileType;
        fs.writeFile(imagePath, data.base64, {encoding: 'base64'}, function (err) {
            if (!err) {
                User.findOne({_id: Mongoose.Types.ObjectId(UserID)}).exec(function (err, user) {
                    if (!err) {
                        user.profileImageURL = imagePath;
                        user.save(callback);
                    }
                });
            }
        });
    });
};

User.getAdminUsers = function (userId, params, callback) {
    var getName, getEmail, getStatus, getCity, getState, getCountry;
    if (params.searchParameter === 'Name') {
        getName = params.searchValue;
    } else if (params.searchParameter === 'Email') {
        getEmail = params.searchValue;
    } else if (params.searchParameter === 'Status') {
        if (params.searchValue === 'true' || params.searchValue === 'True') {
            getStatus = true;
        } else if (params.searchValue === 'false' || params.searchValue === 'False') {
            getStatus = false;
        }
    } else if (params.searchParameter === 'City') {
        getCity = params.searchValue;
    } else if (params.searchParameter === 'State') {
        getState = params.searchValue;
    } else if (params.searchParameter === 'Country') {
        getCountry = params.searchValue;
    }
    var skipItem = params.skipItem || 0,
        itemsperPage = params.itemsperPage || 10,
        sortParameter = params.sortParameter || 'createdAt',
        sortOrder = ((params.sortOrder === 'ascending') ? 1 : -1),
        sort = {},
        skip = parseInt(skipItem),
        limit = parseInt(itemsperPage),
        inputFromDate = params.fromDate,
        toDate = params.toDate;
    sort[sortParameter] = sortOrder;
    var name = new RegExp('^' + getName, "i");
    var email = new RegExp('^' + getEmail, "i");
    var city = new RegExp('^' + getCity, "i");
    var state = new RegExp('^' + getState, "i");
    var country = new RegExp('^' + getCountry, "i");
    var searchMatch = {};
    var searchMatchSecondary = {};
    if (getName) {
        searchMatchSecondary = {firstName: name};
    } else if (getEmail) {
        searchMatchSecondary = {email: email};
    } else if (getCity) {
        searchMatchSecondary = {city: city};
    } else if (getState) {
        searchMatchSecondary = {state: state};
    } else if (getCountry) {
        searchMatchSecondary = {country: country};
    }
    else if (getStatus === false || getStatus === true) {
        searchMatchSecondary = {isActive: getStatus};
    }
    else {
        searchMatchSecondary = {};
    }
    var fromDate = util.getDateWithoutTimeStamp(inputFromDate);
    var todate1 = util.getDateWithoutTimeStamp(toDate);
    var endDate = new Date(todate1.getTime() + (24 * 60 * 60 * 1000));
    var searchMatch = {createdAt: {$gte: fromDate, $lt: endDate}};
    User.aggregate([
        {$match: searchMatch},
        {"$sort": sort},
        {
            $project: {
                "_id": "$_id",
                "firstName": "$firstName",
                "lastName": "$lastName",
                "email": "$email",
                "address": "$address",
                "city": "$city",
                "state": "$state",
                "country": "$country",
                "createdAt": "$createdAt",
                "role": "$role",
                "isActive": "$isActive",
                "aboutMe": "$aboutMe",
                "version": "$version",
                "gender": "$gender"
            }
        },
        {$match: searchMatchSecondary},
        {"$skip": skip},
        {"$limit": limit},
        {
            $project: {
                "_id": "$_id",
                "name": {$concat: ["$firstName", " ", {$ifNull: ["$lastName", " "]}]},
                "email": "$email",
                "address": "$address",
                "city": "$city",
                "state": "$state",
                "country": "$country",
                "createdAt": "$createdAt",
                "role": "$role",
                "isActive": "$isActive",
                "aboutMe": "$aboutMe",
                "version": "$version",
                "gender": "$gender"
            }
        }
    ], callback);
};

User.getUserCount = function (userId, params, callback) {
    var getName, getEmail, getStatus, getCity, getState, getCountry;
    if (params.searchParameter === 'Name') {
        getName = params.searchValue;
    } else if (params.searchParameter === 'Email') {
        getEmail = params.searchValue;
    } else if (params.searchParameter === 'Status') {
        if (params.searchValue === 'true' || params.searchValue === 'True') {
            getStatus = true;
        } else if (params.searchValue === 'false' || params.searchValue === 'False') {
            getStatus = false;
        }
    } else if (params.searchParameter === 'City') {
        getCity = params.searchValue;
    } else if (params.searchParameter === 'State') {
        getState = params.searchValue;
    } else if (params.searchParameter === 'Country') {
        getCountry = params.searchValue;
    }
    var skipItem = params.skipItem || 0,
        itemsperPage = params.itemsperPage || 10,
        sortParameter = params.sortParameter || 'createdAt',
        sortOrder = ((params.sortOrder === 'ascending') ? 1 : -1),
        sort = {},
        skip = parseInt(skipItem),
        limit = parseInt(itemsperPage),
        inputFromDate = params.fromDate,
        toDate = params.toDate;
    sort[sortParameter] = sortOrder;
    var name = new RegExp('^' + getName, "i");
    var email = new RegExp('^' + getEmail, "i");
    var city = new RegExp('^' + getCity, "i");
    var state = new RegExp('^' + getState, "i");
    var country = new RegExp('^' + getCountry, "i");
    var searchMatch = {};
    var searchMatchSecondary = {};
    if (getName) {
        searchMatchSecondary = {firstName: name};
    } else if (getEmail) {
        searchMatchSecondary = {email: email};
    } else if (getCity) {
        searchMatchSecondary = {city: city};
    } else if (getState) {
        searchMatchSecondary = {state: state};
    } else if (getCountry) {
        searchMatchSecondary = {country: country};
    }
    else if (getStatus === false || getStatus === true) {
        searchMatchSecondary = {isActive: getStatus};
    }
    else {
        searchMatchSecondary = {};
    }
    var fromDate = util.getDateWithoutTimeStamp(inputFromDate);
    var todate1 = util.getDateWithoutTimeStamp(toDate);
    var endDate = new Date(todate1.getTime() + (24 * 60 * 60 * 1000));
    var searchMatch = {createdAt: {$gte: fromDate, $lt: endDate}};
    User.aggregate([
        {$match: searchMatch},
        {"$sort": sort},
        {
            $project: {
                "_id": "$_id",
                "firstName": "$firstName",
                "lastName": "$lastName",
                "email": "$email",
                "city": "$city",
                "state": "$state",
                "country": "$country",
                "createdAt": "$createdAt",
                "role": "$role",
                "isActive": "$isActive"
            }
        },
        {$match: searchMatchSecondary},
        {
            $project: {
                "_id": "$_id"
            }
        }
    ], callback);
};

User.updateStatus = function (usersData, callback) {
    var currentStatus = !usersData.isActive;
    User.findOne({$and: [{_id: usersData._id}, {isActive: usersData.isActive}]}).exec(function (err, user) {
        if (!err) {
            if (usersData.state) {
                user.isActive = currentStatus;
            } else {
                if (user.role.indexOf('admin') >= 0) {
                    user.role.pop();
                } else {
                    user.role.push('admin');
                }
            }
            user.save(callback);
        }
    });
};

User.updateUserInfo = function (usersData, callback) {
    var firstName, lastName, name, fullName;
    name = usersData.name;
    fullName = name.split(' ');
    if (fullName.length > 1) {
        lastName = fullName[fullName.length - 1];
        for (var i = 0; i < fullName.length - 1; i++) {
            firstName = fullName[i];
        }
    } else {
        firstName = fullName[0];
        lastName = '';
    }
    usersData.firstName = firstName;
    usersData.lastName = lastName;
    User.findOne({_id: usersData._id}).exec(function (err, user) {
        if (!err) {
            if (usersData.firstName) {
                user.firstName = usersData.firstName;
            }
            if (usersData.lastName) {
                user.lastName = usersData.lastName;
            }
            if (usersData.city) {
                user.city = usersData.city;
            }
            if (usersData.state) {
                user.state = usersData.state;
            }
            if (usersData.country) {
                user.country = usersData.country;
            }
            if (usersData.address) {
                user.address = usersData.address;
            }
            if (usersData.aboutMe) {
                user.aboutMe = usersData.aboutMe;
            }
            if (usersData.versioning) {
                user.version = usersData.versioning;
            }
            if (usersData.gender) {
                user.gender = usersData.gender;
            }
            if (usersData.isAdmin == true) {
                user.role = ['user', 'admin'];
            }
            if (usersData.isAdmin == false) {
                user.role = ['user'];
            }
            if (usersData.isSuperAdmin == true) {
                user.role.push('superadmin');
            }
            if (usersData.isActive) {
                user.isActive = usersData.isActive;
            }
            user.save(callback);
        }
    });
};

User.getRecentUsers = function (params, callback) {
    var sortOrder = -1,
        sortParameter = 'createdAt',
        sort = {};
    sort[sortParameter] = sortOrder;
    User.aggregate([
        {"$sort": sort},
        {"$limit": 5},
        {
            $project: {
                "_id": "$_id",
                "name": {$concat: ["$firstName", " ", {$ifNull: ["$lastName", " "]}]},
                "aboutMe": "$aboutMe",
                "profileImageURL": "$profileImageURL"
            }
        }
    ], callback);
};

User.editRole = function (id, role, callback) {
    User.findOne({_id: new Mongoose.Types.ObjectId(id)}, function (err, user) {
        if (err) throw err;
        else {
            user.role = [];
            user.role = role;
            user.save(callback);
        }
    });
};

User.saveIdea = function (id, idea, callback) {
    User.findOne({_id: new Mongoose.Types.ObjectId(id)}, function (err, user) {
        if (err) throw err;
        else {
            user.savedIdea = {};
            user.savedIdea = idea;
            user.save(callback);
        }
    });
};



User.getSavedIdea = function (id, callback) {
    User.findOne({_id: id}, {
        'savedIdea': 1,
        '_id': 0
    }, callback);
};

User.getTotalUserCount = function (callback) {

    User.aggregate([
        {
            "$group" : {
                "_id" : "_id",
                "total" : {
                    "$sum" : 1
                }
            }
        }
    ], callback);
};


module.exports = User;